package com.snowfeel.sfmall.sys.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.snowfeel.sfmall.core.constants.Constants;
import com.snowfeel.sfmall.core.constants.EntityConstants;
import com.snowfeel.sfmall.core.enums.ResponseCode;
import com.snowfeel.sfmall.core.exception.BizException;
import com.snowfeel.sfmall.core.param.IdParam;
import com.snowfeel.sfmall.core.param.IdsParam;
import com.snowfeel.sfmall.core.vo.Option;
import com.snowfeel.sfmall.core.vo.PageVo;
import com.snowfeel.sfmall.sys.convert.SysDeptConvert;
import com.snowfeel.sfmall.sys.dto.SysDeptParam;
import com.snowfeel.sfmall.sys.mapper.SysDeptMapper;
import com.snowfeel.sfmall.sys.model.SysDept;
import com.snowfeel.sfmall.sys.query.SysDeptQuery;
import com.snowfeel.sfmall.sys.vo.SysDeptVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 部门业务实现类
 *
 * @author haoxr
 * @date 2021-08-22
 */
@Service
public class SysDeptService extends ServiceImpl<SysDeptMapper, SysDept> {

    @Autowired
    private SysDeptConvert deptConvert;

    /**
     * 部门列表
     */
    public PageVo<SysDeptVo> page(SysDeptQuery deptQuery) {
        // 查询参数
        String keywords = deptQuery.getKeywords();
        Integer status = deptQuery.getStatus();

        LambdaQueryWrapper<SysDept> queryWrapper = new LambdaQueryWrapper<SysDept>()
                .like(StrUtil.isNotBlank(keywords), SysDept::getName, keywords)
                .eq(Validator.isNotNull(status), SysDept::getStatus, status)
                .orderByAsc(SysDept::getSort)
                .orderByDesc(SysDept::getCreateTime);
        // 查询数据
        Page<SysDept> page = this.page(new Page<>(deptQuery.getPageNo(), deptQuery.getPageSize()),
                queryWrapper);

        List<SysDeptVo> list = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(page.getRecords())) {
            Set<Long> cacheDeptIds = page.getRecords().stream()
                    .map(SysDept::getId)
                    .collect(Collectors.toSet());

            for (SysDept dept : page.getRecords()) {
                Long parentId = dept.getParentId();
                // 不在缓存ID列表的parentId是顶级节点ID，以此作为递归开始
                if (cacheDeptIds.contains(parentId) == false) {
                    list.addAll(recurDepartments(parentId, page.getRecords()));
                    cacheDeptIds.add(parentId); // 避免重复递归
                }
            }
        }

        //  列表为空说明所有的节点都是独立的
        if (CollectionUtils.isEmpty(list)) {
            list = page.getRecords().stream().map(item -> {
                SysDeptVo deptVO = new SysDeptVo();
                BeanUtil.copyProperties(item, deptVO);
                return deptVO;
            }).collect(Collectors.toList());
        }

        PageVo<SysDeptVo> pageVO = new PageVo<>();
        pageVO.setList(list);
        pageVO.setPages((int) page.getPages());
        pageVO.setTotal(page.getTotal());
        return pageVO;
    }

    /**
     * 递归生成部门层级列表
     *
     * @param parentId
     * @param deptList
     * @return
     */
    public List<SysDeptVo> recurDepartments(Long parentId, List<SysDept> deptList) {
        List<SysDeptVo> list = deptList.stream()
                .filter(dept -> dept.getParentId().equals(parentId))
                .map(dept -> {
                    SysDeptVo deptVO = deptConvert.convertVo(dept);
                    List<SysDeptVo> children = recurDepartments(dept.getId(), deptList);
                    deptVO.setChildren(children);
                    return deptVO;
                }).collect(Collectors.toList());
        return list;
    }


    /**
     * 部门下拉选项
     *
     * @return
     */
    public List<Option> listDeptOptions() {
        List<SysDept> deptList = this.list(new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getStatus, EntityConstants.YES)
                .select(SysDept::getId, SysDept::getParentId, SysDept::getName)
                .orderByAsc(SysDept::getSort)
        );

        List<Option> options = buildDeptTree(deptList);
        return options;
    }

    public Long create(SysDeptParam deptParam) {
        SysDept entity = deptConvert.convertPo(deptParam);
        // 部门路径
        String treePath = generateDeptTreePath(deptParam.getParentId());
        entity.setTreePath(treePath);
        // 保存部门并返回部门ID
        this.save(entity);
        return entity.getId();
    }

    public Long update(Long id, SysDeptParam deptParam) {
        SysDept sysDept = this.getById(id);
        if (Objects.isNull(sysDept)) {
            throw new BizException(ResponseCode.NOT_FOUND);
        }
        // form->entity
        SysDept entity = deptConvert.convertPo(deptParam);
        entity.setId(sysDept.getId());
        // 部门路径
        String treePath = generateDeptTreePath(deptParam.getParentId());
        entity.setTreePath(treePath);
        // 保存部门并返回部门ID
        this.updateById(entity);
        return entity.getId();
    }

    /**
     * 递归生成部门表格层级列表
     *
     * @param depts
     * @return
     */
    public List<Option> buildDeptTree(List<SysDept> depts) {
        if (CollectionUtil.isEmpty(depts)) {
            return Collections.EMPTY_LIST;
        }
        List<Option> returnList = new ArrayList<Option>();
        List<Long> tempList = new ArrayList<>();
        for (SysDept dept : depts) {
            tempList.add(dept.getId());
        }
        for (SysDept dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                Option option = new Option(dept.getId(), dept.getName());
                recursionFn(depts, option);
                returnList.add(option);
            }
        }
        if (CollectionUtils.isEmpty(returnList)) {
            depts.stream().forEach(dept -> {
                Option option = new Option(dept.getId(), dept.getName());
                returnList.add(option);
            });
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysDept> list, Option t) {
        // 得到子节点列表
        List<Option> childList = getChildList(list, t);
        t.setChildren(childList);
        for (Option tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<Option> getChildList(List<SysDept> list, Option t) {
        List<Option> tlist = new ArrayList<Option>();
        Iterator<SysDept> it = list.iterator();
        while (it.hasNext()) {
            SysDept n = it.next();
            if (n.getParentId() != null && n.getParentId() == t.getValue()) {
                Option option = new Option(n.getId(), n.getName());
                tlist.add(option);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysDept> list, Option t) {
        return getChildList(list, t).size() > 0;
    }

    /**
     * 删除部门
     *
     * @param param 部门ID集合
     * @return
     */
    public boolean deleteBatch(IdsParam param) {
        // 删除部门及子部门
        param.getIds().forEach(deptId -> {
            LambdaQueryWrapper<SysDept> queryWrapper = new LambdaQueryWrapper<SysDept>()
                    .eq(SysDept::getId, deptId)
                    .or()
                    .apply("concat (',',tree_path,',') like concat('%,',{0},',%')", deptId);
            this.remove(queryWrapper);
        });
        return true;
    }

    /**
     * 获取部门详情
     *
     * @param param
     * @return
     */
    public SysDeptVo detail(IdParam param) {
        LambdaQueryWrapper<SysDept> queryWrapper = new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getId, param.getId())
                .select(SysDept::getId,
                        SysDept::getName,
                        SysDept::getParentId,
                        SysDept::getStatus,
                        SysDept::getSort);
        SysDept entity = this.getOne(queryWrapper);
        SysDeptVo deptForm = deptConvert.convertVo(entity);
        return deptForm;
    }

    /**
     * 部门路径生成
     *
     * @param parentId
     * @return
     */
    private String generateDeptTreePath(Long parentId) {
        String treePath = null;
        if (Constants.ROOT_NODE_ID.equals(parentId)) {
            treePath = parentId + "";
        } else {
            SysDept parent = this.getById(parentId);
            if (parent != null) {
                treePath = parent.getTreePath() + "," + parent.getId();
            }
        }
        return treePath;
    }

}
